import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:shop/utils/config.dart';
import 'package:shop/utils/token_utils.dart';
import '../route/routes.dart';

// 基础URL（可根据环境切换）
final String _baseUrl = Configs.baseUrl;

// 状态码
enum StatusCode {
  success(200), // 成功
  unauthorized(401), // 未授权（token过期）
  forbidden(403), // 禁止访问
  notFound(404), // 资源不存在
  serverError(500); // 服务器错误

  final int code;
  const StatusCode(this.code);
}

// 新增：自定义未登录异常（区分普通网络异常）
class UnLoginException implements Exception {
  final String message;
  UnLoginException({this.message = "请先登录"});

  @override
  String toString() => "UnLoginException: $message";
}

class DioUtils {
  // 单例模式
  static final DioUtils _instance = DioUtils._internal();
  factory DioUtils() => _instance;

  late Dio _dio;

  // 私有构造函数
  DioUtils._internal() {
    _dio = Dio(BaseOptions(
      baseUrl: _baseUrl,
      headers: {"device-type": "app"},
      connectTimeout: const Duration(seconds: 10),
      receiveTimeout: const Duration(seconds: 10),
      sendTimeout: const Duration(seconds: 10),
      responseType: ResponseType.json,
      contentType: Headers.jsonContentType,
    ));
    _addInterceptors();
  }

  // 添加拦截器
  void _addInterceptors() {
    _dio.interceptors.addAll([
      if (kDebugMode)
        LogInterceptor(
          request: true,
          requestBody: true,
          responseBody: true,
          error: true,
        ),
      // 自定义请求拦截器（新增权限校验逻辑）
      _RequestInterceptor(),
      _ResponseInterceptor(),
    ]);
  }

  // 1. 通用请求方法：新增 needLogin 参数
  Future<T?> request<T>(
      String path, {
        String method = 'GET',
        Map<String, dynamic>? params,
        data,
        Map<String, dynamic>? headers,
        bool needLogin = true, // 新增：是否需要登录权限，默认true
      }) async {
    try {
      // 将权限标识存入请求选项（供拦截器使用）
      final options = Options(
        method: method,
        headers: headers,
        extra: {"needLogin": needLogin}, // 关键：通过extra传递自定义参数
      );

      final response = await _dio.request(
        path,
        queryParameters: method == 'GET' ? params : null,
        data: method != 'GET' ? params ?? data : null,
        options: options,
      );

      if (response.statusCode == StatusCode.success.code) {
        return response.data as T?;
      } else {
        throw NetworkException(
          code: response.statusCode ?? -1,
          message: "请求失败：${response.statusMessage}",
        );
      }
    } on UnLoginException catch (e) {
      // 2. 捕获未登录异常，统一处理跳转
      _handleUnLogin();
      rethrow; // 抛出异常让调用方感知
    } on DioException catch (e) {
      throw _handleDioError(e);
    } catch (e) {
      throw NetworkException(
        code: -1,
        message: "未知错误：${e.toString()}",
      );
    }
  }

  // 3. GET请求：传递 needLogin 参数
  Future<T?> get<T>(
      String path, {
        Map<String, dynamic>? params,
        Map<String, dynamic>? headers,
        bool needLogin = true, // 新增权限参数
      }) async {
    return request<T>(
      path,
      method: 'GET',
      params: params,
      headers: headers,
      needLogin: needLogin, // 传递到request方法
    );
  }

  // 4. POST请求：传递 needLogin 参数
  Future<T?> post<T>(
      String path, {
        Map<String, dynamic>? params,
        data,
        Map<String, dynamic>? headers,
        bool needLogin = true, // 新增权限参数
      }) async {
    return request<T>(
      path,
      method: 'POST',
      params: params,
      data: data,
      headers: headers,
      needLogin: needLogin, // 传递到request方法
    );
  }

  // 处理Dio错误
  NetworkException _handleDioError(DioException e) {
    switch (e.type) {
      case DioExceptionType.connectionTimeout:
        return NetworkException(code: -2, message: "连接超时，请检查网络");
      case DioExceptionType.sendTimeout:
        return NetworkException(code: -3, message: "发送超时，请重试");
      case DioExceptionType.receiveTimeout:
        return NetworkException(code: -4, message: "接收超时，请重试");
      case DioExceptionType.connectionError:
        return NetworkException(code: -5, message: "网络连接错误，请检查网络");
      case DioExceptionType.cancel:
        return NetworkException(code: -6, message: "请求已取消");
      case DioExceptionType.badResponse:
        final code = e.response?.statusCode ?? -7;
        final msg = e.response?.statusMessage ?? "服务器错误";
        // token过期（401）也触发未登录处理
        if (code == StatusCode.unauthorized.code) {
          _handleUnLogin();
        }
        return NetworkException(code: code, message: msg);
      default:
        return NetworkException(code: -100, message: "请求失败：${e.message}");
    }
  }

  // 统一处理未登录（跳转登录页+清除token）
  void _handleUnLogin() async {
    final token = await TokenUtils.getToken();
    if (token != null) {
      TokenUtils.clearToken(); // 清除无效token
    }
    // 跳转登录页（替换当前路由栈，避免返回）
    AppRouter().router.pushReplacement("/login");
    if (kDebugMode) {
      print("未登录或token失效，已跳转登录页");
    }
  }
}

// 5. 自定义请求拦截器：新增权限校验
class _RequestInterceptor extends Interceptor {
  @override
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
    // 1. 从请求配置中获取“是否需要登录”的标识（默认需要）
    final bool needLogin = options.extra["needLogin"] ?? true;

    // 2. 仅对需要登录的接口做 Token 校验
    if (needLogin) {
        final token = await TokenUtils.getToken();
      // 3. 无 Token → 未登录，跳转登录页
      if (token == null || token.isEmpty) {
        // 跳转登录页（替换当前路由，避免返回原页面）
        AppRouter().router.pushReplacement("/login");

        // 阻止无效请求发送，抛出未登录异常
        handler.reject(
          DioException(
            requestOptions: options,
            type: DioExceptionType.cancel,
            error: UnLoginException(),
          ),
          true,
        );
        return;
      }

      // 4. 有 Token → 附加到请求头
      options.headers['Authorization'] = 'Bearer $token';
    }

    // 无需登录或已校验通过 → 继续请求
    handler.next(options);
  }
}

// 自定义响应拦截器（保持不变）
class _ResponseInterceptor extends Interceptor {
  @override
  void onResponse(Response response, ResponseInterceptorHandler handler) {
    if (response.data is Map) {
      final code = response.data['code'] ?? -1;
      final msg = response.data['msg'] ?? "未知错误";
      if (code != 200) {
        return handler.reject(DioException(
          requestOptions: response.requestOptions,
          response: response,
          type: DioExceptionType.badResponse,
          error: NetworkException(code: code, message: msg),
        ));
      }
      response.data = response.data;
    }
    handler.next(response);
  }
}

// 网络异常类（保持不变）
class NetworkException implements Exception {
  final int code;
  final String message;

  NetworkException({required this.code, required this.message});

  @override
  String toString() => "NetworkException: [$code] $message";
}